﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Collections;
using System.IO;


namespace ShareB.Models
{
    #region Publication Configuration models
    public class PubConfModel
    {
        //id da configuração
        public int ConfID { get; set; }

        //nome da configuração
        public string ConfName { get; set; }

        //lista de campos que fazem parte da configuração
        public IList<MetaFieldModel> fieldsConf { get; set; }

        public bool Included { get; set; }

        //inicializações necessárias
        public PubConfModel()
        {
            fieldsConf = new List<MetaFieldModel>();
        }

    }

    //model to register a new confiuration for a publication type
    public class NewPubConfModel : PubConfModel
    {
        //lista de campos possiveis a incluir
        public IList<IncludeMetaModel> includedFields { get; set; }


        public NewPubConfModel()
        {
            includedFields = new List<IncludeMetaModel>();
        }
    }
    #endregion


    #region Publication models

    public class PublicationModel
    {
        //the id of this Publication
        public int PublicationID { get; set; }
        //the id of the author of the message
        public int UserID { get; set; }
        //the username of the author of the message
        public string Username { get; set; }
        //the id of this publication configuration
        public int PubConfID { get; set; }
        //creation date
        public DateTime StartDate { get; set; }
        //last edited date
        //public DateTime EditDate { get; set; }
        //Tittle
        [Required]
        [DisplayName("Tittle")]
        public string Tittle { get; set; }
        //List of fields on this publication
        [Required]
        public IList<FieldModel> Fields { get; set; }
        //List of fields on this publication
        public IList<ClassificationModel> Classif { get; set; }
        //List of fields on this publication
        [Required]
        public ClassificationModel ClassifAlone { get; set; }

        //needed inicializations
        public PublicationModel()
        {
            Fields = new List<FieldModel>();
            ClassifAlone = new ClassificationModel();
            Classif = new List <ClassificationModel>();
        }
    }

    public class NewPublicationModel : PublicationModel
    {
        public PubConfModel configuration { get; set; }

        public NewPublicationModel()
        {
            configuration = new PubConfModel();
        }
    }

    //compact information to be displayed in a users profile and suport the users message management
    public class MessageModel
    {
        //the id of the publication the message refers to
        public int PublicationID { get; set; }
        //the author of the message
        public int UserID { get; set; }
        //wheter this message has been read or not
        public bool Unread { get; set; }

        //incluir a publication talvez ou vai-se buscar depois pelo ID. por pensar melhor
    }

    //Model to implement a kind of a users Inbox messages
    public class MessagesModel
    {
        //List of messages
        List<MessageModel> Messages { get; set; }

        //number of unread messages
        public int NrUnread { get; set; }

    }

    //Model Classification
    public class ClassificationModel
    {
        //the id of this Classification
        public int ClassificationID { get; set; }
        //the id of the publication
        public int PublicationID { get; set; }
        //the id of the user
        public int UserID { get; set; }
        //the num of the classification
        [Required]
        [DisplayName("Classification")]
        public int Classification { get; set; }
    }
    
    #endregion

    public class PubConfService
    {
        ShareBDataContext db = new ShareBDataContext();

        //Get Configurations by ID + Metafields
        public PubConfModel GetConfigurations(int pubID)
        {
            PubConfModel model = new PubConfModel();
            //fetch metafields in the database
            foreach (PublicationConfiguration conf in db.PublicationConfigurations)
            {
                
                if (conf.PubConfID == pubID)
                {
                    model.ConfID = conf.PubConfID;
                    model.ConfName = conf.ConfigurationName;
                    model.fieldsConf = GetMetaFields(conf.PubConfID);
                }
            }

            return model;
        }

        ////Get Configurations by ID + Metafields
        //public PubConfModel GetConfigurations(int pubID)
        //{
        //    PubConfModel model = new PubConfModel();
        //    //fetch metafields in the database
        //    foreach (PublicationConfiguration conf in db.PublicationConfigurations)
        //    {
                
        //        if (conf.PubConfID == pubID)
        //        {
        //            model.ConfID = conf.PubConfID;
        //            model.ConfName = conf.ConfigurationName;
        //            model.fieldsConf = GetMetaFields(conf.PubConfID);
        //        }
        //    }

        //    return model;
        //}

        
        //Get Existing Metafields
        public IList<PubConfModel> GetAllConfigurations()
        {
            IList<PubConfModel> confList = new List<PubConfModel>();

            //fetch metafields in the database
            foreach (PublicationConfiguration conf in db.PublicationConfigurations)
            {
                confList.Add(new PubConfModel
                {
                    ConfID = conf.PubConfID,
                    ConfName = conf.ConfigurationName,
                    fieldsConf = GetMetaFields(conf.PubConfID)
                });
            }
            return confList;
        }

        //Get MetaFields
        public IList<MetaFieldModel> GetMetaFields(int configurationID)
        {
            IList<MetaFieldModel> metaList = new List<MetaFieldModel>();

            //fetch metafields in the database
            foreach (FieldRelation pub in db.FieldRelations)
            {
                if (pub.PubConfID == configurationID)
                {
                    MetaField meta = db.MetaFields.Single(m => m.MetaFieldID == pub.MetaFieldID);
                    metaList.Add(new MetaFieldModel
                    {
                        FieldName = meta.FieldName,
                        FieldType = meta.FieldType,
                        MetaFieldID = meta.MetaFieldID,
                        Locked = meta.Locked
                    });
                }
            }
            return metaList;
        }

        //add new Publication configuration
        public void CreateConf(PubConfModel model)
        {
            //cria a configuraçao e submete-la na bd
            PublicationConfiguration pf = new PublicationConfiguration
            {
                ConfigurationName = model.ConfName
            };

            db.PublicationConfigurations.InsertOnSubmit(pf);

            //for each metafield in the model, create and submit relation in PubConfFields table
            foreach (MetaFieldModel m in model.fieldsConf)
            {
                FieldRelation pub = new FieldRelation
                {
                    PubConfID = model.ConfID,
                    MetaFieldID = m.MetaFieldID,
                    Locked = m.Locked
                };
                db.FieldRelations.InsertOnSubmit(pub);
            }

            //save all changes
            db.SubmitChanges();
        }
        /*
        public MetaFieldModel GetMeta(int id)
        {
            //procurar na bd
            MetaField m = db.MetaFields.Single(meta => meta.MetaFieldID == id);

            if (m != null)
                return new MetaFieldModel
                {
                    FieldName = m.FieldName,
                    FieldType = m.FieldType,
                    MetaFieldID = m.MetaFieldID,
                    Locked = m.Locked
                };
            else return null;
        }

        internal void UpdateMeta(MetaFieldModel model)
        {
            MetaField m = db.MetaFields.Single(meta => meta.MetaFieldID == model.MetaFieldID);
            m.FieldName = model.FieldName;
            m.FieldType = model.FieldType;
            m.Locked = model.Locked;

            db.SubmitChanges();
        }*/
    }

    #region services

    public class PublicationService
    {
        ShareBDataContext db;

        public PublicationService()
        {
            db = new ShareBDataContext();
        }

        // Get Fields by publication ID
        public IList<FieldModel> GetFields(int publicationID)
        {
            IList<FieldModel> fieldList = new List<FieldModel>();

            //fetch metafields in the database
            foreach (Field fil in db.Fields)
            {
                if (fil.PublicationID == publicationID)
                {
                    Field field = db.Fields.Single(m => m.FieldID == fil.FieldID);
                    fieldList.Add(new FieldModel
                    {
                        FieldName = field.FieldName,
                        FieldID = fil.FieldID,
                        MetaFieldID = field.MetaFieldID,
                        FieldValue = fil.FieldValue,
                        PublicationID = fil.PublicationID
                    });
                }
            }
            return fieldList;
        }

        //Get All Publications
        public IList<PublicationModel> GetAllMyPublication(int user)
        {
            IList<PublicationModel> pubList = new List<PublicationModel>();

            //fetch metafields in the database
            foreach (Publication pub in db.Publications)
            {
                if (pub.UserID == user)
                {
                    pubList.Add(new PublicationModel
                    {
                        UserID = pub.UserID,
                        Tittle = pub.Tittle,
                        PublicationID = pub.PublicationID,
                        PubConfID = pub.PubConfID,
                        Fields = GetFields(pub.PublicationID)
                    });
                }
            }
            return pubList;

        }

        //Get Publications
        public PublicationModel GetMyPublication(int pubID)
        {
            PublicationModel pubModel = new PublicationModel();
            if (pubID != 0)
            {
                //fetch metafields in the database
                foreach (Publication pub in db.Publications)
                {
                    if (pub.PublicationID == pubID)
                    {
                        pubModel = new PublicationModel
                            {
                                UserID = pub.UserID,
                                Username = pub.User.Username,
                                StartDate = pub.TimeStamp,
                                //EditDate = pub.TimeStamp,
                                Tittle = pub.Tittle,
                                PublicationID = pub.PublicationID,
                                PubConfID = pub.PubConfID,
                                Fields = GetFields(pub.PublicationID),
                                Classif = GetClassificationByID(pub.PublicationID)
                            };
                    }
                }

            }
            return pubModel;

        }

        public bool ActClassification(PublicationModel pubModel)
        {
            IMembershipService serv = new UserMembershipService();
            PublicationModel pubModelTeste = new PublicationModel();
            pubModelTeste = GetMyPublication(pubModel.PublicationID);

            // ACRESCENTEI ESTA LINHA DE TESTE
            //pubModelTeste.EditDate = System.DateTime.Now;
            //if (pubModel.ClassifAlone != null && pubModel.ClassifAlone.Classification != 0)
            if (pubModel.ClassifAlone != null)
            {
                if (pubModelTeste.Classif != null)
                {
                    pubModel.ClassifAlone.PublicationID = pubModelTeste.PublicationID;
                    //pubModel.ClassifAlone.UserID = pubModelTeste.UserID;
                    pubModel.ClassifAlone.UserID = serv.GetUserID(HttpContext.Current.User.Identity.Name);

                    foreach (ClassificationModel c in pubModelTeste.Classif)
                    {
                        if (serv.GetUserID(HttpContext.Current.User.Identity.Name) == c.UserID)
                        {
                            // JA ESTA INSERIDO, TEMOS QUE FAZER UM UPDATE À BASE DE DADOS
                            UpdateClassification(pubModel.ClassifAlone, c);
                            return true;
                        }
                    }
                    AddClassification(pubModel.ClassifAlone);
                    return true;
                }
                else
                {
                    pubModel.ClassifAlone.PublicationID = pubModelTeste.PublicationID;
                    //pubModel.ClassifAlone.UserID = pubModelTeste.UserID;
                    pubModel.ClassifAlone.UserID = serv.GetUserID(HttpContext.Current.User.Identity.Name);
                    AddClassification(pubModel.ClassifAlone);
                    return true;
                }
            }

            return false;
        }

        // Create one publication
        public bool CreatePublication(PublicationModel model, int pubconfID)
        {

            //if (String.IsNullOrEmpty(model.Tittle)) throw new ArgumentException("Value cannot be null or empty.", "Tittle");
            //foreach (FieldModel cmodel in model.Fields)
            //{
            //    if (String.IsNullOrEmpty(cmodel.FieldValue)) throw new ArgumentException("Value cannot be null or empty.", "Field Value");
            //}
            //if (String.IsNullOrEmpty(model.ClassifAlone.Classification.ToString())) throw new ArgumentException("Value cannot be null or empty.", "Classification");

            // GRAVAR A PUBLICACAO
            Publication pub = new Publication
                    {
                        UserID = model.UserID,
                        PubConfID = model.PubConfID,
                        TimeStamp = System.DateTime.Now,
                        Tittle =  model.Tittle
                    };

            db.Publications.InsertOnSubmit(pub);
            db.SubmitChanges();

            // GRAVAR CAMPOS NO FIELD, INCREMENTALMENTE
            
            foreach (FieldModel cmodel in model.Fields)
            {
                    Field field = new Field
                        {
                            PublicationID = db.Publications.Single(c => c.Tittle == pub.Tittle).PublicationID,
                            //PublicationID = db.Publications.Single(c => c.PublicationID == pub.PublicationID).PublicationID,
                            MetaFieldID = cmodel.MetaFieldID,
                            FieldName = cmodel.FieldName,
                            FieldValue = cmodel.FieldValue
                        };
               
               db.Fields.InsertOnSubmit(field);
               db.SubmitChanges();
                
            }

            // GRAVAR A PONTUACAO
            if (model.ClassifAlone != null)
            {
                //if (model.ClassifAlone.Classification != 0)
                //{
                    Classification clas = new Classification
                    {
                        Classification1 = model.ClassifAlone.Classification,
                        PublicationID = db.Publications.Single(c => c.Tittle == pub.Tittle).PublicationID,
                        UserID = model.UserID
                    };

                    db.Classifications.InsertOnSubmit(clas);
                    db.SubmitChanges();
                       
                //}
            }
            return true;
        }

        // Give one classification
        public IList<ClassificationModel> GetClassificationByID(int pubID)
        {
            IList<ClassificationModel> classList = new List<ClassificationModel>();

            //fetch metafields in the database
            foreach (Classification clas in db.Classifications)
            {
                if (clas.PublicationID == pubID)
                {
                    classList.Add(new ClassificationModel
                    {
                        PublicationID = clas.PublicationID,
                        ClassificationID = clas.ClassificationID,
                        UserID = clas.UserID,
                        Classification = clas.Classification1
                    });
                }
            }
            return classList;
        }

        // Give one classification
        public void AddClassification(ClassificationModel model)
        {
            // GRAVAR A Classificacao
            Classification clas = new Classification
            {
                Classification1 = model.Classification,
                PublicationID = model.PublicationID,
                UserID = model.UserID
            };

            db.Classifications.InsertOnSubmit(clas);
            db.SubmitChanges();
        }

        // Give one classification
        public void UpdateClassification(ClassificationModel modelnovo, ClassificationModel modelantigo)
        {
            Classification clas2 = db.Classifications.Single(c => c.ClassificationID == modelantigo.ClassificationID);
            clas2.PublicationID = modelnovo.PublicationID;
            clas2.UserID = modelnovo.UserID;
            clas2.Classification1 = modelnovo.Classification;

            db.SubmitChanges();
        }

        public void EditPublication(PublicationModel model)
        {
            Publication p = db.Publications.Single(c => c.PublicationID == model.PublicationID);
            
            p.UserID = model.UserID;
            p.Tittle = model.Tittle;
            //p.TimeStamp = System.DateTime.Now;
            p.PublicationID = model.PublicationID;
            p.PubConfID = model.PubConfID;

            //if (String.IsNullOrEmpty(p.Tittle)) throw new ArgumentException("Value cannot be null or empty.", "Tittle");

            db.SubmitChanges();

            // VAI SUBMETER DE NOVO OS FIELDS DAQUELA PUBLICAÇAO ( MESMO QUE NAO TENHAM FEITO ALTERAÇÕES AO MODEL, MAIS SEGURO)

            //IList<Field> fteste = new List<Field>();
            //fteste = db.Fields.Single(c => c.PublicationID == model.PublicationID);
            
            int i = 0;
            foreach (Field f in db.Fields)
            {
                if (f.PublicationID == model.PublicationID)
                {
                    f.FieldName = model.Fields[i].FieldName;
                    f.FieldValue = model.Fields[i].FieldValue;
                    f.MetaFieldID = model.Fields[i].MetaFieldID;
                    //f.PublicationID = model.Fields[i].PublicationID;
                    i++;
                    db.SubmitChanges();
                    //if (String.IsNullOrEmpty(f.FieldValue)) throw new ArgumentException("Value cannot be null or empty.", "Field Value");
                }

            }


            

            // GRAVAR NOVAMENTE A PONTUACAO
            
            if (model.ClassifAlone != null)
            {
                //if (model.ClassifAlone.Classification != 0)
                //{
                    
                    foreach (Classification c in db.Classifications)
                    {
                        if (c.UserID == model.UserID && c.PublicationID == model.PublicationID)
                        {
                            c.Classification1 = model.ClassifAlone.Classification;
                            //c.PublicationID = model.ClassifAlone.PublicationID;
                            //c.UserID = model.ClassifAlone.UserID;
                            //if (String.IsNullOrEmpty(c.Classification1.ToString())) throw new ArgumentException("Value cannot be null or empty.", "Classification");
                        }
                    }

                    db.SubmitChanges();
                //}
            }
        }


    }

 

    #endregion

}